package controllers

import (
	"context"
	"net/http"
	"path/filepath"
	"strings"

	"github.com/goadesign/goa"
)

// DistController implements the dist resource.
type DistController struct {
	*goa.Controller
}

// NewDistController creates a dist controller.
func NewDistController(service *goa.Service) *DistController {
	return &DistController{Controller: service.NewController("DistController")}
}

// FileHandler 重载FileHandler
func (ctrl *DistController) FileHandler(path, filename string) goa.Handler {
	var wc string
	if idx := strings.LastIndex(path, "/*"); idx > -1 && idx < len(path)-1 {
		wc = path[idx+2:]
		if strings.Contains(wc, "/") {
			wc = ""
		}
	}

	return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		fname := filename
		if len(wc) > 0 {
			if m, ok := goa.ContextRequest(ctx).Params[wc]; ok {
				fname = filepath.Join(filename, m[0])
			}
		}
		goa.LogInfo(ctx, "serve file", "name", fname, "route", req.URL.Path)
		dir, name := filepath.Split(fname)
		fs := http.Dir(dir)
		f, err := fs.Open(name)
		if err != nil {
			if len(wc) == 0 {
				return goa.ErrInvalidFile(err)
			}
			fs := http.Dir(filename)
			ff, err := fs.Open("index.html")
			if err != nil {
				return goa.ErrInvalidFile(err)
			}
			f = ff
		}
		defer f.Close()
		d, err := f.Stat()
		if err != nil {
			return goa.ErrInvalidFile(err)
		}
		// use contents of index.html for directory, if present
		if d.IsDir() {
			index := strings.TrimSuffix(name, "/") + "/index.html"
			ff, err := fs.Open(index)
			if err == nil {
				defer ff.Close()
				dd, err := ff.Stat()
				if err == nil {
					name = index
					d = dd
					f = ff
				}
			} else {
				fs := http.Dir(filename)
				ff, err := fs.Open("index.html")
				if err != nil {
					return goa.ErrInvalidFile(err)
				}
				dd, err := ff.Stat()
				if err == nil {
					d = dd
					f = ff
				}
			}
		}

		// serveContent will check modification time
		// Still a directory? (we didn't find an index.html file)
		if d.IsDir() {
			return goa.ErrInvalidFile(nil)
		}
		http.ServeContent(rw, req, d.Name(), d.ModTime(), f)
		return nil
	}
}
